package se.webbzon.oschi01.nbt;

import java.util.ArrayList;

import se.webbzon.oschi01.nbt.TagEvent.Action;


public class ListTag extends AbstractTag<Iterable<Tag<?>>> {
	
	private final TagRing<?> children;
	private byte tagId = 1;
	private boolean empty = true;
	
	public ListTag(TagFactory<Iterable<Tag<?>>> factory, String tagName) {
		super(factory, tagName);
		this.children = new TagRing<Object>(this);
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	boolean addTag(Tag<?> tag) {
		Tag t = tag;
		if (children.addSibling(t,true)) {
			if (empty) {
				empty = false;
				tagId = tag.getFactory().getId();
			}
			return true;
		} else
			return false;
	}
	
	byte getTagId() {
		return tagId;
	}
	
	@Override public boolean canAdopt(Tag<?> child) {
		if (empty)
			return true;
		else
			return child.getFactory().getId() == tagId;
	}

	@Override public long size() {
		long size = 0;
		TagSibling tag = children.getSibling();
		while (tag != children) {
			size += ((Tag<?>) tag).size();
			tag = tag.getSibling();
		}
		return size;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override public Iterable<Tag<?>> getValue() {
		Iterable i = children;
		return i;
	}
	
	@Override public boolean hasChildren() {
		return !empty;
	}

	public TagGeneration<?> getChildren() {
		return children;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override public void setValue(Iterable<Tag<?>> value) {
		children.clear();
		ArrayList<Tag<?>> values = new ArrayList<Tag<?>>();
		int count = 0;
		for (Tag tag : value) {
			if (canAdopt(tag)) {
				values.add(tag);
				children.addSibling(tag,true);
				count++;
			}
		}
		if (count > 0) {
			empty = false;
			tagId = values.get(0).getFactory().getId();
			int[] indicies = new int[count];
			for (int i = 0; i < count; i++)
				indicies[i] = i;
			broadcastEvent(new TagEvent(this,Action.CHILD_ADDED,indicies,values.toArray()));
		}
	}

	@SuppressWarnings("unchecked")
	@Override public Class<Iterable<Tag<?>>> getValueClass() {
		return (Class<Iterable<Tag<?>>>) children.getClass();
	}

	@Override public ListTag clone() {
		ListTag copy = new ListTag(getFactory(),this.toString());
		for (Tag<?> child : children)
			copy.addTag(child.clone());
		return copy;
	}

	@Override public void broadcastEvent(TagEvent event) {
		if (event.source() == this) {
			if (event.getAction() == Action.CHILD_REMOVED && children.isEmpty()) {
				empty = true;
				tagId = 1;
			} else if (empty && event.getAction() == Action.CHILD_ADDED) {
				empty = false;
				tagId = children.getSibling(0).getFactory().getId();
			}
		}
		super.broadcastEvent(event);
	}
	
}
